using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Trigits
{
    public class Triominoe
    {
        private int[] values;
        private float rotation;
        private bool faceUp;
        private Vector2 location;
        private VertexPositionColor[] fillVertices;
        private VertexPositionColor[] lineVertices;
        private AnchoredText[] valueText;
        private SpriteFont font;
        private float radius = 50;
        private float scale = 1;

        //
        //Summary:
        //  Creates a triangular tile with three values on the corners.
        //  
        //Parameters:
        //  a:
        //      The first and lowest value.
        //
        //  b:
        //      The second and middle value.
        //
        //  c:
        //      The third and highest value.
        //
        //  rot:
        //      The rotation in degrees.
        //
        //  faceUp:
        //      Whether the values are exposed or not.
        public Triominoe(int a, int b, int c, float rot, bool faceUp, SpriteFont font, float scale)
        {
            this.font = font;
            values = new int[3];
            values[0] = a;
            values[1] = b;
            values[2] = c;
            this.scale = scale;
            rotation = rot;
            this.faceUp = faceUp;
            location = new Vector2(0.0f, 0.0f);
            radius *= scale;

            fillVertices = new VertexPositionColor[4];
            fillVertices[0].Color = fillVertices[1].Color =
                fillVertices[2].Color = fillVertices[3].Color = Color.PaleGoldenrod;

            lineVertices = new VertexPositionColor[4];
            lineVertices[0].Color = lineVertices[1].Color =
                lineVertices[2].Color = lineVertices[3].Color = Color.Maroon;

            valueText = new AnchoredText[3];
            setVertices();
        }
        public void setRotation(float rot)
        {
            rotation = rot;
            setVertices();
        }
        public float getRotation()
        {
            return rotation;
        }
        public bool isPointingRight()
        {
            if (rotation % 120 == 0)
                return true;
            
            if (rotation % 120 == 60)
                return false;

            throw new Exception("Can only match neatly rotated Triominoes.");
        }
        public int[] getValues()
        {
            return values;
        }
        public int getValue()
        {
            return values[0] + values[1] + values[2];
        }
        public void flip(bool faceUp)
        {
            this.faceUp = faceUp;
        }
        public bool isFaceUp()
        {
            return faceUp;
        }
        public void rotate()
        {
            rotation = rotation % 360;

            if (rotation >= 300)
                rotation = 360;
            else if (rotation >= 240)
                rotation = 300;
            else if (rotation >= 180)
                rotation = 240;
            else if (rotation >= 120)
                rotation = 180;
            else if (rotation >= 60)
                rotation = 120;
            else if (rotation >= 0)
                rotation = 60;

            setVertices();
        }
        public void rotate(float angle)
        {
            rotation += angle;

            while (rotation < 0)
                rotation += 360;
            
            setVertices();
        }
        public void setLocation(Vector2 loc)
        {
            location = loc;
            setVertices();
        }
        public void move(Vector2 distance)
        {
            location = location + distance;
            setVertices();
        }
        public void Update(GameTime gameTime)
        {
            setVertices();
            for (int i = 0; i < 3; i++)
            {
                Vector2 p = new Vector2();
                p.X = (this.location.X + this.lineVertices[i].Position.X) / 2;
                p.Y = (this.location.Y + this.lineVertices[i].Position.Y) / 2;
                valueText[i].setPosition(p);

                valueText[i].setRotation(MathHelper.ToRadians(rotation + i * 120 + 90));
            }
        }
        public void Draw(GraphicsDevice graphics, SpriteBatch spriteBatch, SpriteFont font, BasicEffect effect)
        {
            spriteBatch.Begin();
            effect.CurrentTechnique.Passes[0].Apply();

            graphics.DrawUserPrimitives<VertexPositionColor>(
                PrimitiveType.TriangleStrip, fillVertices, 0, 1);

            graphics.DrawUserPrimitives<VertexPositionColor>(
                PrimitiveType.LineStrip, lineVertices, 0, 3);
            
            if(faceUp)
                for(int i = 0; i < 3; i++)
                    valueText[i].Draw(spriteBatch);

            spriteBatch.End();
        }
        private void setVertices()
        {
            float angle = MathHelper.ToRadians(rotation);
            float angle_incr = MathHelper.ToRadians(120);

            for (int i = 0; i < 3; i++)
            {
                fillVertices[i].Position = new Vector3(
                    location.X + radius * (float)(Math.Cos(angle)),
                    location.Y + radius * (float)(Math.Sin(angle)),
                    0);

                lineVertices[i].Position = new Vector3(
                    location.X + radius * (float)(Math.Cos(angle)),
                    location.Y + radius * (float)(Math.Sin(angle)),
                    0);

                angle += angle_incr;
            }

            fillVertices[3] = fillVertices[0];
            lineVertices[3] = lineVertices[0];

            setText(scale);
        }
        private void setText(float scale)
        {
            for (int i = 0; i < 3; i++)
            {
                Vector2 v = new Vector2(
                    (this.location.X + lineVertices[i].Position.X) / 2,
                    (this.location.Y + lineVertices[i].Position.Y) / 2
                );
                String s = values[i].ToString();
                float r = (MathHelper.ToRadians(rotation + i * 120 + 90));

                valueText[i] = new AnchoredText(font, s, v, r, TextAnchor.MiddleCenter, scale);
            }
        }
        public float getRadius()
        {
            return radius;
        }
        public bool containsPoint(float x, float y)
        {
            Vector2 ab = new Vector2(
                fillVertices[0].Position.X - fillVertices[1].Position.X,
                fillVertices[0].Position.Y - fillVertices[1].Position.Y);
            Vector2 ap = new Vector2(
                fillVertices[0].Position.X - x,
                fillVertices[0].Position.Y - y);
            float abp = ap.X * ab.Y - ap.Y * ab.X;

            Vector2 bc = new Vector2(
                fillVertices[1].Position.X - fillVertices[2].Position.X,
                fillVertices[1].Position.Y - fillVertices[2].Position.Y);
            Vector2 bp = new Vector2(
                fillVertices[1].Position.X - x,
                fillVertices[1].Position.Y - y);
            float bcp = bp.X * bc.Y - bp.Y * bc.X;

            if (abp >= 0 && bcp < 0 ||
                abp < 0 && bcp >= 0)
                return false;

            Vector2 ca = new Vector2(
                fillVertices[2].Position.X - fillVertices[0].Position.X,
                fillVertices[2].Position.Y - fillVertices[0].Position.Y);
            Vector2 cp = new Vector2(
                fillVertices[2].Position.X - x,
                fillVertices[2].Position.Y - y);
            float cap = cp.X * ca.Y - cp.Y * ca.X;

            if (bcp >= 0 && cap < 0 ||
                bcp < 0 && cap >= 0)
                return false;

            return true;
        }
        public Vector2 getLocation()
        {
            return location;
        }
        public Vector2[] getVectors()
        {
            Vector2[] v = new Vector2[3];
            for (int i = 0; i < 3; i++)
            {
                v[i] = new Vector2(fillVertices[i].Position.X, fillVertices[i].Position.Y);
            }

            return v;
        }
    }
}
